package com.miniserver.tql.database.impl;

import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Stack;

import com.miniserver.tql.TqlGlobal;
import com.miniserver.tql.TqlPool;
import com.miniserver.tql.database.ConnectionPool;
import com.miniserver.tql.database.EngineContext;
import com.miniserver.tql.database.EngineFunction;
import com.miniserver.tql.database.ModelConfiguration;

public class EngineContextImpl implements EngineContext {
	private EngineFunction func;
	private ModelConfiguration config;
	private Map<String, String> values;
	private boolean memdbHasTrans = false;
	private boolean physicalHasTrans = false;
	private Connection physicalConn = null;
	private Connection memdbConn = null;
	// 内存数据库的更新操作需要写所有数据库实例
	// 因此所有内存数据库都取回一个链接存入allConns
	private Connection[] allMemdbConns = null;
	private Stack<ConnectionState> states = new Stack<ConnectionState>();

	public EngineContextImpl(ModelConfiguration mcfg, Map<String, String> values, EngineFunction func) {
		this.values = values;
		this.func = func;
		this.config = mcfg;
	}

	@Override
	public String get(String attrName) {
		return this.get(attrName, null);
	}

	@Override
	public String get(String attrName, String defaultAttrValue) {
		if (values.containsKey(attrName)) {
			return values.get(attrName);
		} else {
			return defaultAttrValue;
		}
	}

	@Override
	public void put(String attrName, String attrValue) {
		values.put(attrName, attrValue);
	}

	@Override
	public boolean contains(String attrName) {
		return values.containsKey(attrName);
	}

	@Override
	public EngineFunction getFunction() {
		return this.func;
	}

	@Override
	public ModelConfiguration getModelConfig() {
		return this.config;
	}

	@Override
	public boolean isMemdbMode() {
		if (this.states.empty()) {
			return true;
		} else {
			return this.states.peek().isMemdbMode();
		}
	}

	@Override
	public boolean hasTransaction() {
		if (this.isMemdbMode()) {
			return this.memdbHasTrans;
		} else {
			return this.physicalHasTrans;
		}
	}

	@Override
	public void setHasTransaction(boolean hasTransaction) {
		if (this.isMemdbMode()) {
			this.memdbHasTrans = hasTransaction;
		} else {
			this.physicalHasTrans = hasTransaction;
		}
	}

	@Override
	public Connection getConnection() {
		if (this.isMemdbMode()) {
			if (this.memdbConn != null) {
				return this.memdbConn;
			} else if (this.allMemdbConns != null && this.allMemdbConns.length > 0) {
				int idx = new Random().nextInt(this.allMemdbConns.length);
				return this.allMemdbConns[idx];
			} else {
				return null;
			}
		} else {
			return this.physicalConn;
		}
	}

	@Override
	public void setConnection(Connection conn) {
		if (this.isMemdbMode()) {
			this.memdbConn = conn;
		} else {
			this.physicalConn = conn;
		}
	}

	@Override
	public void destroy() {
		this.closeConnection(this.memdbConn, false);
		this.memdbConn = null;
		//
		if (this.allMemdbConns != null) {
			for (int i = 0; i < this.allMemdbConns.length; i++) {
				this.closeConnection(this.allMemdbConns[i], this.memdbHasTrans);
			}
			this.allMemdbConns = null;
		}
		//
		this.closeConnection(this.physicalConn, this.physicalHasTrans);
		this.physicalConn = null;
	}

	private void closeConnection(Connection conn, boolean hasTrans) {
		if (conn == null) {
			return;
		}
		//
		if (hasTrans) {
			try {
				conn.rollback();
			} catch (Exception e) {
				// ...
			}
		}
		//
		try {
			conn.close();
		} catch (Exception e) {
			// ...
		}
	}

	@Override
	public Connection[] getMemdbConns() {
		return this.allMemdbConns;
	}

	@Override
	public void setMemdbConns(Connection[] conns) {
		this.allMemdbConns = conns;
	}

	@Override
	public void popState() {
		if (!this.states.empty()) {
			this.states.pop();
		}
	}

	/**
	 * 
	 * @param mode
	 *            0 当前库, 1 内存库 2 物理库
	 * @param require
	 *            0 不要求链接 1 读实例 2 写实例
	 * @return
	 * @throws Exception
	 */

	@Override
	public void pushState(int mode, int require) throws Exception {
		if (this.states.empty() || mode != ConnectionState.DM_AUTO) {
			ConnectionState state = new ConnectionState();
			state.setMemdbMode(mode != ConnectionState.DM_PHYSICAL);
			this.states.push(state);
		}
		//
		if (require == ConnectionState.RC_NONE) {
			return;
		}
		//
		if (this.states.peek().isMemdbMode()) {
			if (require == ConnectionState.RC_WRITE) {
				if (this.allMemdbConns == null) {
					String memdbName = this.getModelConfig().getParamValue(TqlGlobal.CK_MOMERY_DATABASE);
					List<TqlPool> pools = TqlGlobal.getTqlMaster().getMemdbPools(memdbName);
					if (pools == null || pools.size() == 0) {
						throw new Exception("服务器内部错误:创建内存数据库失败！");
					}
					//
					this.allMemdbConns = new Connection[pools.size()];
					for (int i = 0; i < this.allMemdbConns.length; i++) {
						this.allMemdbConns[i] = pools.get(i).getConnection();
					}
				}
			} else if (this.getConnection() == null) {
				String memdbName = this.getModelConfig().getParamValue(TqlGlobal.CK_MOMERY_DATABASE);
				TqlPool pool = TqlGlobal.getTqlMaster().getMemdbPool(memdbName);
				if (pool == null) {
					throw new Exception("服务器内部错误:创建内存数据库失败！");
				} else {
					this.memdbConn = pool.getConnection();
				}
			}
		} else if (this.physicalConn == null) {
			String physicaldb = this.getModelConfig().getParamValue(TqlGlobal.CK_PHYSICAL_DATABASE);
			ConnectionPool pool = TqlGlobal.getTqlMaster().getPhysicalPool(physicaldb);
			if (pool == null) {
				throw new Exception("服务器内部错误:创建数据库链接池失败！");
			} else {
				this.physicalConn = TqlGlobal.getTqlMaster().getPhysicalPool(physicaldb).getConnection();
			}
		}
	}
}
